package com.syblood.app.handler;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.ImageReader;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

import com.syblood.app.camera.callback.ICameraGLSurfaceViewCallback;
import com.syblood.app.camera.watermark.utils.SizeUtils;
import com.syblood.app.ui.activities.base.BaseActivity;
import com.syblood.app.utils.ConstantsUtils;
import com.syblood.app.utils.ToastUtil;

import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 单个相机的处理器
 */
public class CameraOneHandler {
    private static final String TAG = ConstantsUtils.TAG_HEAD + CameraOneHandler.class.getSimpleName();
    private static final String FRAGMENT_DIALOG = "dialog";

    private static BaseActivity baseActivity;

    private CameraManager manager;
    private CameraDevice mCameraDevice;

    /**
     * 当前相机的ID。
     */
    private String mCameraId;
    //当前相机预览视图
    private SurfaceTexture mTextureView;

    //这几个属性是启动时才会创建
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private ImageReader mImageReader;
    private Size mPreviewSize;
    /**
     * 一个信号量以防止应用程序在关闭相机之前退出。
     */
    private Semaphore mCameraOpenCloseLock;

    private ICameraGLSurfaceViewCallback mCameraGLSurfaceViewCallback = new ICameraGLSurfaceViewCallback() {
        @Override
        public void onSurfaceViewCreate(SurfaceTexture texture, int width, int height) {
            setUpCameraOutputs(width, height);
        }

        @Override
        public void onSurfaceViewChange(int width, int height) {
            setUpCameraOutputs(width, height);
        }
    };
    private CameraCaptureSession mCaptureSession;

    public CameraOneHandler(BaseActivity baseActivity, SurfaceTexture mTextureView, CameraManager manager, String mCameraId) {
        this.baseActivity = baseActivity;
        this.mTextureView = mTextureView;
        this.manager = manager;
        this.mCameraId = mCameraId;
        mCameraOpenCloseLock = new Semaphore(mCameraId.hashCode());
        Log.d(TAG, "CameraOneHandler creat mTextureView = " + mTextureView);
    }


    private CameraDevice.StateCallback getStateCallback() {
        return new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice cameraDevice) {
                // 打开相机时调用此方法。 在这里开始相机预览。
                Log.d(TAG, "CameraDevice.StateCallback onOpened :");
                mCameraOpenCloseLock.release();
                mCameraDevice = cameraDevice;
                //创建CameraPreviewSession
                createCameraPreviewSession(mTextureView, mPreviewSize, mCameraDevice, mImageReader, mHandler);
            }

            @Override
            public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                Log.d(TAG, "CameraDevice.StateCallback onDisconnected :");
                mCameraOpenCloseLock.release();
                cameraDevice.close();
                mCameraDevice = null;
            }

            @Override
            public void onError(@NonNull CameraDevice cameraDevice, int error) {
                Log.d(TAG, "CameraDevice.StateCallback onError :");
                mCameraOpenCloseLock.release();
                cameraDevice.close();
                mCameraDevice = null;
                mCaptureSession = null;
            }
        };

    }


    /**
     * 处理与JPEG捕获有关的事件
     */
    private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureProgressed(@NonNull CameraCaptureSession session,
                                        @NonNull CaptureRequest request,
                                        @NonNull CaptureResult partialResult) {
        }

        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                       @NonNull CaptureRequest request,
                                       @NonNull TotalCaptureResult result) {
        }
    };

    /**
     * 初始化
     */
    public void initView() {
        if (mHandlerThread == null) {
            startHandlerThread();
//            setCameraView(mTextureView);
            openCameraOne();
        } else {
            stopHandlerThread();
        }
    }

//    private void setCameraView(SurfaceTexture mTextureView) {
//        if (mTextureView.isAvailable()) {
//            //设置相机输出
//            setUpCameraOutputs(mTextureView.getWidth(), mTextureView.getHeight());
////            configureTransform(mTextureView.getWidth(), mTextureView.getHeight(), mTextureView, mPreviewSize);
//        } else {
//            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
//        }
//    }


    private void openCameraOne() {
        //检查权限
        if (ContextCompat.checkSelfPermission(baseActivity, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            requestCameraPermission();
            return;
        }
        try {
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                Log.d(TAG, "openCameraOne Time out waiting to lock camera opening.");
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }
            //打开相机预览
            CameraDevice.StateCallback stateCallback = getStateCallback();
            manager.openCamera(mCameraId, stateCallback, mHandler);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "openCameraOne error:" + e.getMessage());
        }
    }

//    /**
//     * Configures the necessary {@link Matrix} transformation to `mTextureView`.
//     * This method should be called after the camera preview size is determined in
//     * setUpCameraOutputs and also the size of `mTextureView` is fixed.
//     *
//     * @param viewWidth  The width of `mTextureView`
//     * @param viewHeight The height of `mTextureView`
//     */
//    private void configureTransform(int viewWidth, int viewHeight, AutoFitTextureView mTextureView, Size mPreviewSize) {
//        if (null == mTextureView || null == mPreviewSize) {
//            return;
//        }
//        int rotation = baseActivity.getWindowManager().getDefaultDisplay().getRotation();
//        Matrix matrix = new Matrix();
//        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
//        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
//        float centerX = viewRect.centerX();
//        float centerY = viewRect.centerY();
//        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
//            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
//            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
//            float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(), (float) viewWidth / mPreviewSize.getWidth());
//            matrix.postScale(scale, scale, centerX, centerY);
//            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
//        } else if (Surface.ROTATION_180 == rotation) {
//            matrix.postRotate(180, centerX, centerY);
//        }
//        mTextureView.setTransform(matrix);
//    }

    /**
     * 设置与相机相关的成员变量。
     *
     * @param width  相机预览的可用尺寸宽度
     * @param height 相机预览的可用尺寸的高度
     */
    private void setUpCameraOutputs(int width, int height) {
        CameraManager manager = (CameraManager) baseActivity.getSystemService(Context.CAMERA_SERVICE);
        try {
            //获取相机的相关参数
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraId);
            // 不使用前置摄像头。
            StreamConfigurationMap configurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            // 对于静态图像拍摄，使用最大的可用尺寸。
            Size largest = Collections.max(Arrays.asList(configurationMap.getOutputSizes(ImageFormat.JPEG)), new SizeUtils.CompareSizesByArea());
            Integer mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
            //设置预览大小，mImageReader监听回调也是这个大小
            Log.d(TAG, "largest = " + largest.toString());
            mPreviewSize = SizeUtils.getSize(baseActivity, configurationMap, mSensorOrientation, largest, width, height);
            mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, 2);
            Log.d(TAG, "mPreviewSize = " + mPreviewSize.toString());
            Log.d(TAG, "setUpCameraOutputs = " + width+"x"+height);
        } catch (CameraAccessException e) {
            Log.w("初始化摄像头失败", e);
        } catch (NullPointerException e) {
            Log.w("初始化摄像头失败", e);
            //不支持Camera2API
            ToastUtil.show(baseActivity, "初始化摄像头失败");
        }
    }

    /**
     * 为相机预览创建新的CameraCaptureSession
     */
    private void createCameraPreviewSession(SurfaceTexture surfaceTexture, Size mPreviewSize,
                                            CameraDevice mCameraDevice, ImageReader mImageReader, Handler mHandler) {
        try {

            // 将默认缓冲区的大小配置为我们想要的相机预览的大小。 设置分辨率
            surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

            // 预览的输出Surface。
            Surface previewSurface = new Surface(surfaceTexture);

            //设置了一个具有输出Surface的CaptureRequest.Builder。
            final CaptureRequest.Builder mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 这里一定分别add两个surface，一个Textureview的，一个ImageReader的，如果没add，会造成没摄像头预览，或者没有ImageReader的那个回调！！
            mPreviewRequestBuilder.addTarget(previewSurface);

            CameraCaptureSession.StateCallback stateCallback = getStateCallback(mPreviewRequestBuilder);
            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface), stateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 检查权限
     */
    private void requestCameraPermission() {
        baseActivity.requestPermission("请给予相机、存储权限，以便app正常工作",
                new BaseActivity.Callback() {
                    @Override
                    public void success() {
                    }

                    @Override
                    public void failed() {
                        Toast.makeText(baseActivity, "未授予相机、存储权限！", Toast.LENGTH_SHORT).show();
                    }
                },
                new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE});
    }

    /**
     * 启动一个HandlerThread
     */
    private void startHandlerThread() {
        mHandlerThread = new HandlerThread("Camera_" + mCameraId);
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());
    }

    /**
     * 停止一个HandlerThread
     */
    public void stopHandlerThread() {
        if (mImageReader != null) {
            mImageReader.getSurface().release();
            mImageReader.close();
            mImageReader = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCaptureSession = null;
            mCameraDevice = null;
        }
        //重新初始化，如果直接退出有消息还未处理
        if (mHandler != null) {
            mHandler.getLooper().quitSafely();
        }

        if (mHandlerThread != null) {
            // mHandlerThread.quitSafely();
            mHandlerThread = null;
        }
        if (mHandler != null) {
            mHandler = null;
        }
    }

    private CameraCaptureSession.StateCallback getStateCallback(CaptureRequest.Builder mPreviewRequestBuilder) {
        //创建一个CameraCaptureSession来进行相机预览。
        return new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession captureSession) {
                // 相机已经关闭
                if (null == mCameraDevice) {
                    return;
                }
                Log.d(TAG, "CameraCaptureSession.StateCallback onConfigured :");
                // 会话准备好后，我们开始显示预览
                try {
                    mCaptureSession = captureSession;
                    // 自动对焦应
                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    // 最终开启相机预览并添加事件
                    CaptureRequest mPreviewRequest = mPreviewRequestBuilder.build();
                    mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mHandler);

                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                Log.d(TAG, "CameraCaptureSession.StateCallback onConfigureFailed :");
                ToastUtil.show(baseActivity, "配置失败");
            }
        };
    }


    public ICameraGLSurfaceViewCallback getCameraGLSurfaceViewCallback() {
        return mCameraGLSurfaceViewCallback;
    }

    public boolean isPreview() {
        return mCameraDevice != null && mCaptureSession != null;
    }

    public boolean isOpenCamera() {
        return mCameraDevice != null;
    }

}
